﻿using CPPEI.Coolzon.Common;
using CPPEI.Coolzon.Service.Contract;
using CPPEI.Coolzon.ServiceProxy;
using CPPEI.Coolzon.ServiceProxy.MainServiceRef;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CPPEI.Coolzon.UI.Views
{
    /// <summary>
    /// 切换主服务器的线程
    /// </summary>
    public class SwitchMainServerThread
    {
        private static object s_lockObj = new object();

        private static Thread s_thread;
        private static bool s_isRunning = false;
        private static long s_latestTicks = 0;
        private static EventWaitHandle s_waitHandle;

        /// <summary>
        /// 启动切换主服务器的线程。
        /// 启动线程之后，会向当前可用的服务发送切换为主服务器的指令。
        /// 当指令成功执行之后，线程关闭。
        /// </summary>
        public static void Start()
        {
            lock (s_lockObj)
            {
                if (s_thread == null && s_isRunning == false)
                {
                    s_waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);

                    s_thread = new Thread(Running);
                    s_thread.Name = "SwitchMainServerThread";
                    s_isRunning = true;
                    Logger.DebugToTag(Library.LogTag, "切换主服务线程启动");
                    s_thread.Start();
                }
            }
        }

        /// <summary>
        /// 关闭切换主服务的线程
        /// </summary>
        public static void Stop()
        {
            lock(s_lockObj)
            {
                if (s_thread != null && s_isRunning)
                {
                    s_isRunning = false;
                    // 等待线程结束
                    s_waitHandle.WaitOne();
                    Logger.DebugToTag(Library.LogTag, "切换主服务线程停止");
                }
            }
        }

        private static void Running()
        {
            Logger.DebugToTag(Library.LogTag, "切换主服务线程运行开始");

            #region 发送禁用交互的指令
            CPPEI.Coolzon.Event.UI.UIEventBus.PublishAsync(new CPPEI.Coolzon.Event.UI.UIDisableInteractiveEvent("正在切换主服务器中"));
            #endregion

            while (s_isRunning)
            {
                if (DateTime.Now.Ticks - s_latestTicks > TimeSpan.FromSeconds(1).Ticks)
                {
                    if (ValidateMainServerConnectionState())
                    {
                        break;
                    }
                    if(SendSwitchMainServerRequest())
                    {
                        break;
                    }
                    s_latestTicks = DateTime.Now.Ticks;
                }

                Thread.Sleep(100);
            }

            Logger.DebugToTag(Library.LogTag, "切换主服务线程运行结束");

            s_waitHandle.Set();

            s_isRunning = false;
            s_thread = null;

            #region 发送启用交互的指令
            CPPEI.Coolzon.Event.UI.UIEventBus.Publish(new CPPEI.Coolzon.Event.UI.UIEnableInteractiveEvent());
            #endregion
        }

        private static bool ValidateMainServerConnectionState()
        {
            if(string.IsNullOrWhiteSpace(UIContext.Current.MainServerIP) || UIContext.Current.MainServerPort == 0)
            {
                return false;
            }
            for (int index = 0; index < ClientProxyManager.Instance.Proxies.Count; index++)
            {
                MainServiceProxy proxy = ClientProxyManager.Instance.Proxies[index];
                if(string.Equals(proxy.IP, UIContext.Current.MainServerIP) && proxy.Port == UIContext.Current.MainServerPort)
                {
                    return true;
                }
            }
            return false;
        }


        /// <summary>
        /// 向服务器发送切换请求
        /// </summary>
        /// <returns>true：已经向主服务器发送成功，flase:没有发送成功，还需要再发送</returns>
        private static bool SendSwitchMainServerRequest()
        {
            bool isSuccess = false;

            // 将要被设置为主服务器的代理对象
            MainServiceProxy mainProxy = null;
                    Request request =null;

            // 是否向本轮要设置为主服务器的主服务发送切换主服务请求是否成功
            bool isSendToMainServerSuccess = false;

            for (int index = 0; index < ClientProxyManager.Instance.Proxies.Count; index++)
            {
                #region 获取proxy，检测并发送请求
                MainServiceProxy proxy = ClientProxyManager.Instance.Proxies[index];
                if (proxy.State == ServiceProxyState.Connected)
                {
                    if (mainProxy == null)
                    {
                        // 发现第一个可用的服务代理
                        mainProxy = proxy;

                        ReqSwitchMainServerData requestData = new ReqSwitchMainServerData();
                        requestData.MainServerIP = mainProxy.IP;
                        requestData.MainServerPort = mainProxy.Port;

                        // 发送设置为主服务的请求
                        request = RequestUtil.BuildRequest(UIContext.Current.ControlDomainId,
                            UIContext.Current.UserIdentity,
                            SCENARIO.CONNECT,
                            COMMAND.CONNECT.SWITCHMAINSERVER,
                            REQUEST_MODE.ALL,
                            requestData);
                    }
                    else
                    {
                        //向上一个想要被设置为主服务器的主服务代理发送请求失败，转而将本次的proxy设置为主服务器
                        if (!isSendToMainServerSuccess)
                        {
                            mainProxy = proxy;

                            ReqSwitchMainServerData requestData = new ReqSwitchMainServerData();
                            requestData.MainServerIP = mainProxy.IP;
                            requestData.MainServerPort = mainProxy.Port;

                            // 发送设置为主服务的请求
                            request = RequestUtil.BuildRequest(UIContext.Current.ControlDomainId,
                                UIContext.Current.UserIdentity,
                                SCENARIO.CONNECT,
                                COMMAND.CONNECT.SWITCHMAINSERVER,
                                REQUEST_MODE.ALL,
                                requestData);
                        }
                    }

                    try
                    {
                        Logger.DebugToTag(Library.LogTag, "向服务器{0}:{1}发送切换主服务为{2}:{3}的请求",
                            proxy.IP,
                            proxy.Port,
                            mainProxy.IP,
                            mainProxy.Port);
                        proxy.Client.SendRequest(request);
                        if (mainProxy == proxy)
                        {
                            //发送请求完毕，需要等待服务器回应，
                            //本地记录本次发送的目标服务器为正在被切换为主服务器的服务器信息
                            UIContext.Current.UpdateMainServer4Switching(new Server(proxy.IP, proxy.Port));

                            isSuccess = true;
                            isSendToMainServerSuccess = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        // 发送失败
                        Logger.ErrorToTag(Library.LogTag, "向服务器{0}:{1}发送切换主服务为{2}:{3}的请求出错,ex:{4}",
                            proxy.IP,
                            proxy.Port,
                            mainProxy.IP,
                            mainProxy.Port,
                            ex);
                    }
                }
                #endregion
            }

            return isSuccess;
        }
    }
}
